<template>
  <div id="app">
    <div v-show="selectResult.length > 0" style="text-align: center;" v-html="selectResultStr()"></div>
    <div class="echarts-wrapper">
      <div style="height: 600px;" ref="echartsId" id="echartsId"></div>
      <div ref="boxSelect" class="box-select"></div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts'

export default {
  data() {
    return {
      selectionDiv: {},
      selectionPoint: {},
      dataSource: [],
      selectResult: [],
      option: {
        color: ['#000000'],
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          }
        },
        legend: {
          left: 'center',
          top: '5%',
        },
        grid: {
          left: '10%',
          top: '17%',
          right: '8%',
          bottom: '7%',

        },
        dataZoom: [
          {
            type: 'inside',
            start: 0,
            end: 100,
          },
        ],
      }
    }
  },
  mounted() {
    this.selectionDiv = this.$refs.boxSelect
    fetch('/echartsData.txt').then(res => {
      return res.text()
    }).then(res => {
      this.dataSource = JSON.parse(res)
      this.initEcharts(this.dataSource)
    })
  },
  methods: {
    initEcharts(list) {
      this.option.series = [
        {
          type: "line",
          smooth: true,
          symbol: 'none',
          itemStyle: {
            color: '#ffffff',
            normal: {
              lineStyle: {
                width: 1, // 0.1的线条是非常细的了
              },
            },
          },
          data: list.map(item => item.value)
        }
      ]

      this.option.xAxis = {
        type: 'category',
        data: list.map(item => item.createTime),
      }
      this.option.yAxis = {
        type: 'value',
        min: 40,
        max: 90
      }
      this.echartsInstance = echarts.init(document.querySelector('#echartsId'));
      this.echartsInstance.setOption(this.option);
      this.boxSelectEvent()
    },
    boxSelectEvent() {
      this.echartsGetZr = this.echartsInstance.getZr() // 为了监听折线图空白区域鼠标事件
      // 对右键默认事件阻止
      this.echartsGetZr.on('contextmenu', () => {
        event.preventDefault()
      })
      setTimeout(() => {
        this.echartsGetZr.on('mousedown', (e) => {
          // 获取鼠标按下坐标点
          if (e.which === 3) {
            const {offsetX, offsetY} = e;
            this.selectionPoint = {offsetX, offsetY};
            // 并设置选择框 初始位置、宽高
            this.selectionDiv.style.left = offsetX + "px";
            this.selectionDiv.style.top = offsetY + "px";
            this.selectionDiv.style.width = "0px";
            this.selectionDiv.style.height = "0px";
            // 对move、up事件进行监听
            this.echartsGetZr.on("mousemove", this.mousemove);
            this.echartsGetZr.on("mouseup", this.mouseup);
          }

        })
      }, 1000)
    },
    mousemove(e) {
      const x = e.offsetX
      const y = e.offsetY
      const width = Math.abs(this.selectionPoint.offsetX - x);
      const height = Math.abs(this.selectionPoint.offsetY - y);
      // 根据移动坐标 和 初始坐标，计算处宽高
      this.selectionDiv.style.width = width + "px";
      this.selectionDiv.style.height = height + "px";
      this.selectionDiv.style.visibility = "visible";
      // 如果移动的坐标 比 初始坐标小，需要切换选择框的位置
      x < this.selectionPoint.offsetX && (this.selectionDiv.style.left = x + "px");
      y < this.selectionPoint.offsetY && (this.selectionDiv.style.top = y + "px");
    },
    mouseup(e) {
      const {offsetX, offsetY} = e;
      const width = Math.abs(this.selectionPoint.offsetX - offsetX);
      const height = Math.abs(this.selectionPoint.offsetY - offsetY);
      this.selectionDiv.style.visibility = "hidden";
      this.echartsGetZr.off("mousemove", this.mousemove);
      this.echartsGetZr.off("mouseup", this.mouseup);
      if (width > 0 && height > 0) {
        // 对鼠标放开坐标和初始坐标进行判断，看谁小，谁就是左上角的坐标
        this.boxSelectOfPoint({
          offsetX: offsetX < this.selectionPoint.offsetX ? offsetX : this.selectionPoint.offsetX,
          offsetY: offsetY < this.selectionPoint.offsetY ? offsetY : this.selectionPoint.offsetY,
          width,
          height,
        });
      }
    },

    boxSelectOfPoint(result) {
      const {offsetX, offsetY, width, height} = result;
      // type dataItem = { x: string, y: string|number, index: number }
      // dataList: Array<dataItem>
      //  对这些数据进行收集，方便处理。 实际项目中比这个复杂很多，这里是简化过的
      const dataList = []

      this.dataSource.forEach((item, index) => {
        const x = item.createTime
        const y = item.value

        // 得到一个转换的坐标
        let p = this.echartsInstance.convertToPixel('grid', [x, Number(y)])
        //
        const flag = p[0] > offsetX && p[0] < offsetX + width && p[1] > offsetY && p[1] < offsetY + height;

        if (flag) {
          dataList.push({
            x, y: parseFloat(y), index
          })
        }
      })

      if (dataList.length > 0) {
        this.selectResult = dataList
        this.echartsInstance.setOption({
          // 在实际项目中是多条曲线的，如果让多条曲线高亮，则数组
          visualMap: [
            {
              type: "piecewise",
              show: false,
              dimension: 0,
              seriesIndex: 0, // 这里需要和之前的  series 对上
              piecewise: true,
              outOfRange: {
                // color: ['#00000', 'red'][index]
                color: ['#00000'][0] // 这里如果多条曲线的话 则需要一一对应非框选中的颜色，
              },
              pieces: [
                {
                  gt: dataList[0].index,
                  lt: dataList[dataList.length - 1].index,
                  color: "rgba(41,11,236,0.68)",//大于0小于12为蓝色
                },
              ]
            }
          ]
        })
      }
    },
    getAvgValue(list) {
      if (list.length > 1) {
        return (list.reduce((acc, cur) => acc + cur, 0) / list.length).toFixed(2)
      }
    },
    selectResultStr() {
      if (this.selectResult.length === 0) return ''
      return `<span style='margin-right: 30px;'>框选时间: <span style="font-size: 16px;font-weight: bold;">${this.selectResult[0].x} - ${this.selectResult[this.selectResult.length - 1].x}</span>
                平均值： <span style="font-size: 16px;font-weight: bold;">${this.getAvgValue(this.selectResult.map(item => item.y))}</span></span>`
    },
  }
}
</script>

<style>
.echarts-wrapper{
  margin: 40px auto;
  background: #f9f9f9;
  border-radius: 10px;
  position: relative;
  width: 1000px;
}

.box-select{
  position: absolute;
  width: 0;
  height: 0;
  border: 1px solid #0c8fcf;
  background: rgba(12, 143,227, 0.5);
}
</style>
